package com.dyb.nio.future;

import com.google.common.util.concurrent.*;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Guava异步回调和Java的FutureTask异步回调，本质的不同在于：
 * · Guava是非阻塞的异步回调，调用线程是不阻塞的，可以继续执行自己的业务逻辑。
 * · FutureTask是阻塞的异步回调，调用线程是阻塞的，在获取异步结果的过程中，一直阻塞，等待异步线程返回结果。
 */
public class GuavaFuture {

    public static void main(String[] args) throws InterruptedException {
        GuavaFuture future = new GuavaFuture();
        future.run();
    }

    public void run () throws InterruptedException {
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        ExecutorService jPool = Executors.newFixedThreadPool(1);
        // google executor
        ListeningExecutorService gPool = MoreExecutors.listeningDecorator(jPool);
        Callable<Boolean> myJob = new MyJob();
        ListenableFuture<Boolean> listenableFuture = gPool.submit(myJob);

        // 非阻塞回调
        Futures.addCallback(listenableFuture, new FutureCallback<Boolean>() {
            @Override
            public void onSuccess(@Nullable Boolean result) {
                if (result) {
                    System.out.println(Thread.currentThread().getName() + "\t任务执行成功");
                    countDownLatch.countDown();
                }
            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println(Thread.currentThread().getName() + "\t任务执行失败");
            }
        }, gPool);

        countDownLatch.await();
        System.out.println("任务执行完毕，准备关闭线程池");
        gPool.shutdown();
    }

    class MyJob implements Callable<Boolean> {
        @Override
        public Boolean call() throws Exception {
            System.out.println(Thread.currentThread().getName() + "\t开始执行任务");
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + "\t结束执行任务");
            return true;
        }
    }
}
